package world.snowcrystal.component;

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.stereotype.Component;
import world.snowcrystal.dto.ChatroomMessage;
import world.snowcrystal.service.ChatroomService;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;


@Component
@Log4j2
public class MessageCacheStompChannelInterceptor implements ChannelInterceptor {

    private ChatroomService chatroomService;


    @Autowired
    public MessageCacheStompChannelInterceptor(ChatroomService chatroomService) {
        this.chatroomService = chatroomService;
        log.info("MessageCacheStompChannelInterceptor initialized");
    }


    /**
     * Invoked after the completion of a receive regardless of any exception that
     * have been raised thus allowing for proper resource cleanup.
     * <p>Note that this will be invoked only if {@link #preReceive} successfully
     * completed and returned {@code true}.
     *
     * @since 4.1
     */
    @Override
    public void afterReceiveCompletion(@Nullable Message<?> message,
                                       MessageChannel channel,
                                       @Nullable Exception ex) {
        if (ex != null) {
            log.info("received complete message,but exception has been thrown: {}", ex.getMessage());
            return;
        }
        if (message != null && message.getPayload() instanceof ChatroomMessage msg) {
            log.info("The message is null");

            CompletableFuture.supplyAsync(() -> {
                Future<Boolean> future = chatroomService.addNewMessageAsync(msg);
                Boolean result;
                if (future.isDone()) {
                    return future.resultNow();
                } else {
                    try {
                        result = future.get(4L, TimeUnit.SECONDS);
                    } catch (Exception e) {
                        return e;
                    }
                    return result;
                }
            }).thenAcceptAsync((res) -> {
                if (res instanceof Boolean b && b) {
                    log.info("The message is added to cache successfully");
                } else {
                    log.info("The message is not added to cache successfully.It seems like some collision happened or cache is not available");
                }
            });

        }
    }
}
